from gevent import monkey
from public.config import config

if config.GEVENT_MODE:
    monkey.patch_all()

import sys
import socket
import redis
import caches
import logging
import winerror
import win32event
import win32service
import win32timezone
import servicemanager
import win32serviceutil
from flask import Flask
from flask_cors import CORS
from flask import g, make_response
from flask import jsonify, request, render_template
from sqlalchemy.orm import scoped_session
from flasgger import Swagger, swag_from
import models
from apis import api_routes
from waitress import serve
from public.config import Configs
from gevent import pywsgi as wsgi
from security.security import encode_jwt
from security.security import decode_jwt
from models.users.users import Users
from models.logs.logs import Logs
from public.local import datetime_type


formatter = "%(asctime)s - %(levelname)s: %(message)s"
logging.basicConfig(level=logging.INFO, format=formatter)

app = Flask(__name__, static_folder='static')
# app = Flask(__name__, static_folder='static', static_url_path="")

CORS(app=app, supports_credentials=True)
app.config['JSON_AS_ASCII'] = False
# app.config['JSON_SORT_KEYS'] = False
app.config['JSONIFY_MIMETYPE'] = "application/json;charset=utf-8"

app.register_blueprint(api_routes, url_prefix='/api')

config = Configs()
if config.DEVELOP is True:
    Swagger(app, config={"specs_route": "/api/docs"}, merge=True)


@app.before_request
def before_request_func():
    g.cache = redis.Redis(connection_pool=caches.POOL)
    g.session = scoped_session(models.SessionFactory)
    token = request.headers.get('token')
    if token is not None:
        re_dict = decode_jwt(token)
        if re_dict['code'] == 200:
            g.token = encode_jwt(re_dict)
        else:
            g.token = None
    else:
        g.token = None


@app.errorhandler(400)
def error_handler_400(err):
    g.session.rollback()
    return make_response(jsonify({'status': 400, 'msg': '客户端发送请求异常'})), 400


@app.errorhandler(401)
def error_handler_401(err):
    return make_response(jsonify({'status': 401, 'msg': '未登录状态'})), 400


@app.errorhandler(403)
def error_handler_404(err):
    return make_response(jsonify({'status': 403, 'msg': '没有权限操作'})), 403


@app.errorhandler(404)
def error_handler_404(err):
    return make_response(jsonify({'status': 404, 'msg': '访问页面不存在'})), 404


@app.errorhandler(405)
def error_handler_405(err):
    return make_response(jsonify({'status': 405, 'msg': '请求方法不对'})), 405


@app.errorhandler(500)
def error_handler_500(err):
    g.session.rollback()
    return make_response(jsonify({'status': 500, 'msg': '服务器内部出错'})), 500


@app.teardown_request
def teardown_request_func(exc):
    if request.method in ["POST", "PUT", "DELETE"]:
        g.session.commit()
    g.session.close()


class AppServiceApiViSu8080(win32serviceutil.ServiceFramework):
    _svc_name_ = "AppServiceApiViSu8080"
    _svc_display_name_ = "AppServiceApiViSu8080"
    _svc_description_ = "AppServiceApiViSu8080"

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
        self.http_server = wsgi.WSGIServer(listener=("0.0.0.0", config.SERVER_PORT), application=app, log=None)
        self.SvcStop = self.http_server.stop
        self.SvcDoRun = self.http_server.serve_forever


if __name__ == '__main__':
    server, server_ip = "", "127.0.0.1"
    try:
        server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        server.connect(("8.8.8.8", 80))
        server_ip = server.getsockname()[0]
    except OSError:
        server.close()

    if len(sys.argv) == 1:
        try:
            servicemanager.Initialize()
            servicemanager.PrepareToHostSingle(AppServiceApiViSu8080)
            servicemanager.StartServiceCtrlDispatcher()
        except Exception as details:
            if details == winerror.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
                win32serviceutil.usage()
    else:
        win32serviceutil.HandleCommandLine(AppServiceApiViSu8080)

    logging.info(msg="http://{}:{}/api/docs".format(server_ip, config.SERVER_PORT))
    wsgi.WSGIServer(listener=("0.0.0.0", config.SERVER_PORT), application=app, log="default").serve_forever()
